home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v7n17.arc / DCACHE.ASM < prev    next >
Assembly Source File  |  1988-09-13  |  55KB  |  1,036 lines

  1. ;==========================================================================
  2. ;  DCACHE.COM - A fixed disk cache for the IBM Personal Computer.
  3. ;  PC Magazine, Vol 7 # 17
  4. ;--------------------------------------------------------------------------
  5. CODE          SEGMENT PARA PUBLIC 'CODE'
  6.               ASSUME CS:CODE
  7.               ORG    2CH
  8. ENV_SEG       DW     ?                      ;Segment of the environment block
  9.               ORG    80H
  10. TAIL_LENGTH   DB     ?                      ;Length of the command tail
  11.  
  12.               ORG    100H
  13. ENTRY:        JMP    MAIN_ENTRY
  14. ;--------------------------------------------------------------------------
  15. ; Data Area
  16. ;--------------------------------------------------------------------------
  17. PROGRAM       DB     'DCACHE 1.0 (c) 1988 Ziff Communications Co.',13,10
  18.               DB     'PC Magazine ',254,' Douglas Boling',13,10,'$',26
  19.  
  20. ENABLED       DB     1                      ;0 = cache disabled, 1 = enabled
  21. EMS_FLAG      DB     0                      ;use EMS ram flag, 1 = use EMS
  22. EMS_HANDLE    DW     0                      ;handle for EMS memory.
  23.  
  24. ADDR_MASK     DW     001EH                  ;Default mask set for 64K cache
  25. SIZE_MASK     DW     0
  26. EMS_MASK      DW     0                      ;used to sel. the proper EMS page
  27.  
  28. DISK_NUM      DB     80H                    ;number of fixed disk to cache
  29. PAGE_SIZE     DB     8                      ;size of cache page
  30. MAX_HEAD      DW     ?                      ;maximum value of head parameter
  31. MAX_SECTOR    DW     ?                      ;maximum value of sector
  32. MAX_SEGMENT   DW     ?                      ;last segment of data cache
  33.  
  34. DOSBOFFSET    DW     ?                      ;offset of dos data buffer
  35. DOSBSEGMENT   DW     ?                      ;sector of dos data buffer
  36. NUM_OF_SEC    DB     ?                      ;number of sectors requested
  37. DISK_FUNCT    DB     ?                      ;function requested
  38. SECTOR_NUM    DW     ?                      ;sector parameter from dos call
  39. HEAD_NUM      DB     ?                      ;head parameter
  40. CYLINDER_NUM  DW     ?                      ;cylinder parameter
  41.  
  42. SEGMENT_PTR   DW     0                      ;pointers into the cache
  43. PAGE_PTR      DW     0
  44. LOG_SEC_HIGH  DW     0                      ;Logical sector number of disk
  45. LOG_SEC_LOW   DW     0                      ;  request.
  46. LAST_BAD_PAGE DW     -1                     ;stores the last page that
  47.                                             ;contained an error
  48. LOOKUPTABLE   DW     OFFSET DATA_START      ;offset of lookup table
  49. CACHE_SEGMENT DW     0                      ;segment of cache data
  50.  
  51. OLD_DISK_INT  LABEL  DWORD                  ;old bios interrupt 13h vector
  52. OLD_INT13H    DW     2 DUP (?)
  53. ;-----------------------------------------------------------------------------
  54. ; This routine intercepts the bios disk calls.
  55. ; Entry: ah - disk function      (All other registers specific to disk read.)
  56. ;        al - number of sectors                es:bx - pointer to data buffer
  57. ;        ch - Cylinder number                     dh - Head number
  58. ;        cl - 7,6 Cyl. high. 5-0 sector number    dl - drive number
  59. ;-----------------------------------------------------------------------------
  60. DISK_INT      PROC   FAR
  61.               ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  62.               CMP    CS:ENABLED,0           ;See if cache enabled
  63.               JE     SKIP_CACHE
  64.               CMP    DL,CS:DISK_NUM         ;See if the correct disk
  65.               JNE    SKIP_CACHE
  66.               STI                           ;Allow interrupts
  67.               CMP    AH,2                   ;If any other function besides
  68.               JE     CACHE_IT               ;  read or write, reset cache.
  69.               CMP    AH,3
  70.               JE     CACHE_IT1
  71.               CMP    AH,1                   ;If just checking the last status
  72.               JE     SKIP_CACHE             ;  skip cache, but don't reset.
  73. RESET_CMD:
  74.               PUSH   ES                     ;If the command is not a simple
  75.               PUSH   CS                     ;  read, write, or status, assume
  76.               POP    ES                     ;  the worst and clear the lookup
  77.               ASSUME ES:CODE                ;  table.
  78.               CALL   RESET_CACHE
  79.               POP    ES
  80.               ASSUME ES:NOTHING
  81. SKIP_CACHE:
  82.               JMP    CS:OLD_DISK_INT        ;jmp to bios disk routine.
  83. ;--------------------------------------------------------------------------
  84. ;Compute the logical sector number from the cylinder, head, and sector.
  85. ;--------------------------------------------------------------------------
  86. CACHE_IT:
  87.               CMP    AL,CS:PAGE_SIZE        ;For disk read, cache reads of
  88.               JA     SKIP_CACHE             ;  a page or less.
  89. CACHE_IT1:
  90.               PUSH   DS                     ;save registers
  91.               PUSH   DI
  92.               PUSH   SI
  93.               PUSHF
  94.               PUSH   AX
  95.               PUSH   BX
  96.               PUSH   CX
  97.               PUSH   DX
  98.               PUSH   CS                     ;set ds to code segment
  99.               POP    DS
  100.               ASSUME DS:CODE
  101. ;--------------------------------------------------------------------------
  102. ;Store calling parameters.
  103. ;--------------------------------------------------------------------------
  104.               MOV    DOSBOFFSET,BX          ;save dos pointer to its data
  105.               MOV    DOSBSEGMENT,ES         ;  buffer.
  106.               MOV    BX,CX                  ;copy cx
  107.               AND    BX,003FH               ;strip all but the sector number
  108.               MOV    SECTOR_NUM,BX          ;save sector number
  109.               MOV    HEAD_NUM,DH            ;save head number
  110.               MOV    NUM_OF_SEC,AL          ;save the number of sectors needed
  111.               MOV    DISK_FUNCT,AH          ;save function called.
  112. ;--------------------------------------------------------------------------
  113. ;Compute logical sector number from the cylinder, head, and sector parameters.
  114. ;--------------------------------------------------------------------------
  115.               XCHG   CL,CH                  ;create full 10 bit cylinder num.
  116.               ROL    CH,1                   ;  the top 2 bits are in ch bits
  117.               ROL    CH,1                   ;  7 and 6. roll them into bits
  118.               AND    CH,03H                 ;  1 and 2.
  119.               MOV    CYLINDER_NUM,CX        ;save the cylinder number
  120.               MOV    AX,CX                  ;copy cylinder number for multiply
  121.               MOV    BL,DH                  ;get head number out of dx
  122.               MUL    MAX_HEAD               ;multiply cylinder to make room
  123.               XOR    BH,BH                  ;clear high byte of head value
  124.               ADD    AX,BX                  ;add in head.
  125.               MUL    MAX_SECTOR             ;multiply by max sector value
  126.               ADD    AX,SECTOR_NUM          ;add sector number
  127.               ADC    DX,0                   ;propigate carry.
  128.               MOV    LOG_SEC_HIGH,DX        ;save logical sector number
  129.               MOV    LOG_SEC_LOW,AX
  130. ;--------------------------------------------------------------------------
  131. ;Store values needed later.
  132. ;--------------------------------------------------------------------------
  133.               MOV    BH,AL
  134.               SHL    BH,1
  135.               AND    BX,3E00H
  136.               MOV    PAGE_PTR,BX            ;save page index
  137.               AND    BH,30H
  138.               MOV    SI,BX                  ;save page index for cache load
  139. ;--------------------------------------------------------------------------
  140. ;Point the segment register to the proper DOS memory block
  141. ;--------------------------------------------------------------------------
  142.               MOV    BX,AX                  ;copy logical sector low
  143.               MOV    CL,5
  144.               SHL    BX,CL                  ;Convert logical sector number to
  145.               AND    BX,SIZE_MASK           ;  cache page index
  146.               ADD    BX,CACHE_SEGMENT
  147.               MOV    SEGMENT_PTR,BX         ;save segment index
  148.               MOV    BX,AX                  ;copy logical sector number
  149.               MOV    DI,LOOKUPTABLE         ;use di to point to lookup table
  150. ;--------------------------------------------------------------------------
  151. ;Check for a read or a write
  152. ;--------------------------------------------------------------------------
  153.               CMP    DISK_FUNCT,2
  154.               JNE    DISK_WRITE
  155.               JMP    DISK_READ
  156. ;--------------------------------------------------------------------------
  157. ;Process bios write calls.
  158. ;--------------------------------------------------------------------------
  159. DISK_WRITE:
  160.               MOV    CL,AL                  ;See if the write crosses a page
  161.               AND    CL,07H                 ; boundry. If > 8, it does.
  162.               MOV    CH,NUM_OF_SEC
  163.               ADD    CL,CH
  164.               CMP    CL,PAGE_SIZE           ;If the write crosses a page
  165.               JA     WRITE_UPDATE_SKP       ;  boundry, skip the update and
  166.               CMP    EMS_FLAG,0             ;  just purge the cache.
  167.               JE     WRITE_SKP_EMS
  168.               CALL   EMS_SETUP              ;access the EMS page bx=logsec_low
  169. WRITE_SKP_EMS:
  170.               PUSH   AX
  171.               CALL   CHECK_HIT              ;Check to see if the data is in
  172.               POP    AX                     ;  the cache.
  173.               JNE    EXIT_AND_RESTORE       ;If miss, skip all this stuff
  174. ;--------------------------------------------------------------------------
  175. ;Since the data is in the cache, update just the stuff to be written
  176. ;--------------------------------------------------------------------------
  177.               XOR    CL,CL
  178.               MOV    DI,PAGE_PTR            ;Load the pointers for the data
  179.               MOV    SI,DOSBOFFSET          ;  move. ch already contains the
  180.               MOV    ES,SEGMENT_PTR         ;  number of sectors to move. cx
  181.               MOV    DS,DOSBSEGMENT         ; then contains the number of
  182.               ASSUME DS:NOTHING,ES:NOTHING  ;  words to move.
  183.               CLD
  184.               REP    MOVSW                  ;Copy the data to be written into
  185.               PUSH   CS                     ;  the cache.
  186.               POP    DS
  187.               ASSUME DS:CODE
  188.               JMP    SHORT EXIT_AND_RESTORE
  189. ;--------------------------------------------------------------------------
  190. ;If the write crosses a page boundry, just delete the entry from the table.
  191. ;--------------------------------------------------------------------------
  192. WRITE_UPDATE_SKP:
  193.               MOV    SI,AX                  ;Save logical sector low logical
  194.               MOV    CL,PAGE_SIZE           ;  sector high will be fine in dx.
  195.               DEC    CH
  196. DISK_WRITE1:
  197.               CMP    CH,CL                  ;If the number of sectors is less
  198.               JA     DISK_WRITE2            ;  than the page size, decriment
  199.               MOV    CL,CH                  ;  by the number of sectors
  200. DISK_WRITE2:
  201.               PUSH   CX
  202.               CALL   CHECK_HIT                ;Check to see if the sector
  203.               POP    CX
  204.               JNE    DISK_WRITE3              ;is in table. Purge the tag if
  205.               MOV    WORD PTR [DI][BX],0FFFFH ;this is a hit.
  206. DISK_WRITE3:
  207.               PUSH   SI                     ;Save copy of logical sector num
  208.               SUB    CH,CL
  209.               MOV    BL,CL                  ;Subtract the page size from the
  210.               XOR    BH,BH                  ;  number of sectors written. Add
  211.               ADD    SI,BX                  ;  to the logical sector number.
  212.               ADC    DL,0
  213.               MOV    AX,SI                  ;Move logical sector low to ax.
  214.               POP    BX                     ;Get sector before add for compare
  215.               XOR    BX,AX                  ;If there is no difference in the
  216.               TEST   BL,08H                 ;  logical page after the inc then
  217.               JNZ    DISK_WRITE1            ;  exit the loop.
  218. ;--------------------------------------------------------------------------
  219. ;restore the registers for the bios call.
  220. ;--------------------------------------------------------------------------
  221. EXIT_TO_BIOS:
  222.               POP    DX                     ;jump to the bios interrupt as if
  223.               POP    CX                     ;  we were not here.
  224.               POP    BX
  225.               POP    AX
  226.               POPF
  227.               MOV    ES,DOSBSEGMENT
  228.               POP    SI
  229.               POP    DI
  230.               POP    DS
  231.               JMP    CS:OLD_DISK_INT
  232. ;--------------------------------------------------------------------------
  233. ;Exit to bios and restore EMS if necessary
  234. ;--------------------------------------------------------------------------
  235. EXIT_AND_RESTORE:
  236.               CMP    EMS_FLAG,0
  237.               JE     EXIT_TO_BIOS
  238.               MOV    AH,48H                 ;Restore EMS configuration
  239.               MOV    DX,EMS_HANDLE
  240.               INT    67H
  241.               OR     AH,AH
  242.               JE     EXIT_TO_BIOS
  243. INT_EMS_ERR:
  244.               MOV    ENABLED,0              ;EMS error, assume the worst and
  245.               JMP    SHORT EXIT_TO_BIOS     ;  disable the cache.
  246. ;--------------------------------------------------------------------------
  247. ;Process bios read calls.
  248. ;--------------------------------------------------------------------------
  249. DISK_READ:
  250.               ASSUME DS:CODE
  251. ;If using Expanded memory, get the needed segments.
  252.               CMP    EMS_FLAG,0
  253.               JE     INT_DOS_MEM
  254.               CALL   EMS_SETUP
  255. INT_DOS_MEM:
  256. ;--------------------------------------------------------------------------
  257. ;Convert logical sector number to an index into the lookup table.
  258. ;--------------------------------------------------------------------------
  259.               XOR    CL,CL                  ;clear sector counter
  260.               CALL   CHECK_HIT              ;see if we have a hit
  261.               CMP    AX,LAST_BAD_PAGE       ;If this page has a bad sector
  262.               JE     EXIT_AND_RESTORE       ;  don't fetch it.
  263.               MOV    WORD PTR [DI][BX],AX   ;update the look up table.
  264. ;--------------------------------------------------------------------------
  265. ;if we need 2 pages, check to see if the other page is in the cache
  266. ;--------------------------------------------------------------------------
  267.               MOV    AX,LOG_SEC_LOW         ;Add the number of sectors needed
  268.               MOV    CH,AL                  ;  to the displacment in the page
  269.               AND    CH,07H                 ;  if > 8, we need 2 pages.
  270.               ADD    CH,NUM_OF_SEC
  271.               CMP    CH,PAGE_SIZE
  272.               JLE    END_OF_CHK             ;we only need 1 page
  273.               CMP    SI,03000H
  274.               JNE    CHK_2ND_PAGE
  275.               MOV    DX,SEGMENT_PTR         ;check to see if we are at the
  276.               CMP    DX,MAX_SEGMENT         ;  very top of the cache and we
  277.               JB     CHK_2ND_PAGE
  278.               MOV    [DI][BX],0FFFFH         ;clear lookup table
  279.               JMP    SHORT EXIT_AND_RESTORE  ;skip cache.
  280. ;--------------------------------------------------------------------------
  281. ;adjust the index into the lookup table to check for the second page.
  282. ;--------------------------------------------------------------------------
  283. CHK_2ND_PAGE:
  284.               MOV    DX,LOG_SEC_HIGH        ;we need 2 pages, check to see if
  285.               XOR    BH,BH                  ;  the other page is in the cache.
  286.               MOV    BL,NUM_OF_SEC
  287.               ADD    AX,BX                  ;Do this by adding the number of
  288.               ADC    DL,0                   ;  sectors needed to the starting
  289.               CALL   CHECK_HIT              ;  logical sector number.
  290.               JE     END_OF_CHK             ;skip next if second page hit.
  291.               MOV    WORD PTR [DI][BX],AX   ;update the look up table.
  292.               MOV    AL,PAGE_SIZE
  293.               CMP    CL,AL                  ;If we need only the second page,
  294.               JNE    END_OF_CHK             ;  adjust the starting pointers
  295.               ADD    SI,1000H               ;  into the cache.
  296.               XOR    AH,AH
  297.               ADD    LOG_SEC_LOW,AX
  298.               ADC    LOG_SEC_HIGH,0
  299. END_OF_CHK:
  300. ;--------------------------------------------------------------------------
  301. ;Now that we have checked for the data in the cahe, jump to the right routine
  302. ;--------------------------------------------------------------------------
  303.               CMP    CL,0                   ;check the number of sectors to
  304.               JE     CACHE_HIT              ;  read from the disk.
  305. ;--------------------------------------------------------------------------
  306. ;The request is a cache miss. Load the data needed from the disk to the cache.
  307. ;--------------------------------------------------------------------------
  308. CACHE_MISS:
  309.               XOR    CH,CH
  310.               MOV    DI,CX                  ;save the number of sectors needed
  311. ;--------------------------------------------------------------------------
  312. ;Use the logical sector number to compute the new calling parameters.
  313. ;--------------------------------------------------------------------------
  314.               XOR    CX,CX                  ;clear a place for the sector num
  315.               MOV    DX,LOG_SEC_HIGH        ;put the logical sector number
  316.               MOV    AX,LOG_SEC_LOW         ;  into dx,ax
  317.               AND    AX,0FFF8H              ;clear off the odd sector
  318.               JNE    SET_REGS               ;if the resulting logical sector
  319.               OR     DX,DX                  ;  number is 0, modify the calling
  320.               JNE    SET_REGS               ;  parameters to allow for the
  321.               INC    AX                     ;  sectors starting at 1.
  322.               ADD    SI,200H                ;si holds the cache target address
  323.               DEC    DI                     ;di holds the number of sectors
  324. SET_REGS:                                   ;  to fetch.
  325.               DIV    MAX_SECTOR
  326.               OR     CX,DX                  ;save the remainder (sector num)
  327.               JNE    SET_REGS1              ;Since the sector number can not
  328.               MOV    CX,MAX_SECTOR          ;  be zero, check for this and
  329.               DEC    AX                     ;  correct if necessary.
  330. SET_REGS1:
  331.               XOR    DX,DX                  ;remove the remainder
  332.               DIV    MAX_HEAD
  333. ;--------------------------------------------------------------------------
  334. ;put cylinder and sector parameters into their proper registers.
  335. ;--------------------------------------------------------------------------
  336.               MOV    DH,DL                  ;move head to proper register.
  337.               XCHG   AL,AH                  ;Put the cylinder number into the
  338.               ROR    AL,1                   ;  strange, but required registers
  339.               ROR    AL,1
  340.               OR     CX,AX
  341. ;--------------------------------------------------------------------------
  342. ;Compute data buffer inside cache.
  343. ;--------------------------------------------------------------------------
  344.               MOV    BX,SI                  ;Point the data buffer for the
  345.               MOV    ES,SEGMENT_PTR          ;  call to the proper cache page.
  346.               ASSUME ES:NOTHING
  347. ;--------------------------------------------------------------------------
  348. ;complete the parameters for the bios call.
  349. ;--------------------------------------------------------------------------
  350.               MOV    AX,DI                  ;get the number of sectors to read
  351.               MOV    AH,02H                 ;read data from disk
  352.               MOV    DL,DISK_NUM            ;access the correct disk
  353. ;--------------------------------------------------------------------------
  354. ;Set up parameters and call real bios int 13h.
  355. ;--------------------------------------------------------------------------
  356.               PUSH   AX
  357.               PUSHF
  358.               CALL   OLD_DISK_INT
  359.               POP    SI
  360.               JC     BIOS_ERROR             ;if an error ocurred, deal with it
  361. ;--------------------------------------------------------------------------
  362. ;Cache hit. Transfer the data from the cache to the dos buffer.
  363. ;--------------------------------------------------------------------------
  364. CACHE_HIT:
  365.               MOV    DI,DOSBOFFSET          ;Load es:di with the dos data
  366.               MOV    ES,DOSBSEGMENT         ;  buffer.
  367.               ASSUME ES:NOTHING
  368.               MOV    CH,NUM_OF_SEC          ;Put number of words to transfer
  369.               XOR    CL,CL                  ;  into cx.
  370.               MOV    SI,PAGE_PTR            ;Load ds:si with the location of
  371.               MOV    DS,SEGMENT_PTR         ;  the data in the cache.
  372.               ASSUME DS:NOTHING
  373.               CLD
  374.               REP    MOVSW                  ;Transfer the data from the cache
  375.               PUSH   CS
  376.               POP    DS
  377.               ASSUME DS:CODE
  378. EXIT_TO_CALLER:                             ;  to the caller of int 13h
  379. ;--------------------------------------------------------------------------
  380. ;Restore EMS configuration if necessary.
  381. ;--------------------------------------------------------------------------
  382.               CMP    EMS_FLAG,0             ;Check to see if we are using
  383.               JE     CALLER_EXIT_SKIP       ;  ems memory.
  384.               MOV    AH,48H
  385.               MOV    DX,EMS_HANDLE          ;If so, restore the mapping
  386.               INT    67H                    ;  context used before this
  387.               OR     AH,AH                  ;  interrupt.
  388.               JE     CALLER_EXIT_SKIP
  389.               JMP    INT_EMS_ERR
  390. CALLER_EXIT_SKIP:
  391.               POP    DX
  392.               POP    CX
  393.               POP    BX
  394.               POP    AX
  395.               POPF
  396.               XOR    AX,AX                  ;Clear ax to indicate 0 return
  397.               POP    SI                     ;  code.
  398.               POP    DI
  399.               POP    DS
  400.               CLC                           ;Clear carry to indicate no error.
  401.               RET    2                      ;Return but keep current flags
  402. ;-----------------------------------------------------------------------------
  403. ;Error routine
  404. ;-----------------------------------------------------------------------------
  405. BIOS_ERROR:
  406.               ASSUME DS:CODE
  407.               MOV    AX,LOG_SEC_LOW           ;Get logical sector, convert it
  408.               MOV    DX,LOG_SEC_HIGH          ; into an index into the
  409.               MOV    DI,LOOKUPTABLE           ; lookup table, then erase the
  410.               CALL   CHECK_HIT                ;  tag.
  411.               MOV    WORD PTR [DI][BX],0FFFFH
  412.               MOV    CX,SI                    ;See if we were reading 2
  413.               CMP    CL,PAGE_SIZE             ;  pages. If so, clear next
  414.               JLE    BIOS_ERROR1              ;  entry in the lookup table.
  415.               ADD    BX,2
  416.               MOV    WORD PTR [DI][BX],0FFFFH
  417. BIOS_ERROR1:
  418.               MOV    LAST_BAD_PAGE,AX
  419.               XOR    AX,AX
  420.               MOV    DL,DISK_NUM            ;Reset disk system using
  421.               PUSHF                         ;  bios int 13 function 0.
  422.               CALL   OLD_DISK_INT
  423.               JMP    EXIT_AND_RESTORE
  424. DISK_INT      ENDP
  425. ;-----------------------------------------------------------------------------
  426. ;EMS Setup This routine saves the current state of the EMS driver, then
  427. ;          loads in the proper EMS page needed for the cache.
  428. ;Entry: bx - low word of logical sector number
  429. ;-----------------------------------------------------------------------------
  430. EMS_SETUP     PROC   NEAR
  431.               ASSUME DS:CODE
  432.               PUSH   AX
  433.               PUSH   DX
  434.               MOV    CL,5
  435.               SHR    BX,CL                  ;Convert logical sector num to
  436.               AND    BX,EMS_MASK            ;  a physical EMS page number.
  437. ;--------------------------------------------------------------------------
  438. ;Save current state of EMS driver
  439. ;--------------------------------------------------------------------------
  440.               MOV    AH,47H                 ;Save state function
  441.               MOV    DX,EMS_HANDLE
  442.               INT    67H                    ;call EMS driver
  443.               OR     AH,AH                  ;check for error
  444.               JNE    EMS_SETUP_ERR
  445. ;--------------------------------------------------------------------------
  446. ;Get the proper EMS pages from the EMS driver.
  447. ;--------------------------------------------------------------------------
  448.               MOV    AX,4400H               ;map EMS memory to cache segment
  449.               INT    67H
  450.               OR     AH,AH                  ;check for EMS error
  451.               JNE    EMS_SETUP_ERR
  452.               POP    DX
  453.               POP    AX
  454.               RET
  455. EMS_SETUP_ERR:
  456.               ADD    SP,6                   ;clean up stack
  457.               JMP    INT_EMS_ERR
  458. EMS_SETUP     ENDP
  459. ;-----------------------------------------------------------------------------
  460. ;Check hit. This routine checks the lookup table for a match.
  461. ;Entry: dl,ax logical sector number.  Exit: ZF set = hit,  ZF clear, miss
  462. ;       cl = number of sectors to fetch     cl = updated number of sectors
  463. ;       di = base of lookup table
  464. ;-----------------------------------------------------------------------------
  465. CHECK_HIT     PROC   NEAR
  466.               ASSUME DS:CODE
  467.               AND    AX,0FFF8H              ;remove the page index.
  468.               OR     AX,DX                  ;add in the top 3 bits
  469.               MOV    BX,AX                  ;copy the log sec num to bx to
  470.               SHR    BX,1                   ;  create the table index.
  471.               SHR    BX,1
  472.               AND    BX,ADDR_MASK          ;Use the addr mask to limit the
  473.               CMP    AX,WORD PTR [DI][BX]  ;  size of the lookup table
  474.               JE     CHECK_HIT1            ;Check for a hit.
  475.               ADD    CL,PAGE_SIZE          ;cache miss, grab a page of sectors
  476. CHECK_HIT1:
  477.               RET
  478. CHECK_HIT     ENDP
  479. ;-----------------------------------------------------------------------------
  480. ;Reset Cache. Routine clears the cache look up table.
  481. ;Entry ds - segment of the lookup table, and the lookup table offset
  482. ;-----------------------------------------------------------------------------
  483. RESET_CACHE   PROC   NEAR
  484.               ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  485.               PUSH   DI
  486.               PUSH   CX
  487.               PUSH   AX
  488.               MOV    AX,0FFFFH
  489.               MOV    DI,ES:LOOKUPTABLE      ;point di to the lookup table
  490.               MOV    CX,ES:ADDR_MASK        ;compute size of the lookup table
  491.               SHR    CX,1
  492.               INC    CX
  493.               REP    STOSW                  ;write ffff to each entry in the
  494.               POP    AX                     ;  lookup table.
  495.               POP    CX
  496.               POP    DI
  497.               RET
  498. RESET_CACHE   ENDP
  499. ;--------------------------------------------------------------------------
  500. ;Safe place to clear lookup table.
  501. ;--------------------------------------------------------------------------
  502. INSTALL1:
  503.               ASSUME DS:CODE                ;DS points to code segment
  504.               PUSH   CS
  505.               POP    ES                     ;point es to lookup table segment
  506.               ASSUME ES:NOTHING
  507.               CALL   RESET_CACHE            ;Clear lookup table
  508.               POP    CX                     ;get state of enable flag
  509.               MOV    ENABLED,CL             ;Terminate and stay resident
  510.               INT    21H                    ;  with 0 return code.
  511. ;-------------------------------------------------------------------------
  512. ;Data area not needed by resident routine.
  513. ;-------------------------------------------------------------------------
  514.               EVEN                          ;start lookup table on even byte
  515. DATA_START    =      $
  516.  
  517. ;=========================================================================
  518. ;Non-resident code.
  519. ;-------------------------------------------------------------------------
  520. LOOKUP_SIZE   DW     0                      ;size of the lookup table
  521. TERM_MEM      DW     0                      ;amount of memory needed at end.
  522. ALRDY_IN_MEM  DB     0                      ;flag indicating cache installed.
  523. OTHER_SEG     DW     0                      ;segment of installed copy
  524. EMS_HEADER    DB     'EMMXXXX0'             ;Header of EMS driver.
  525.  
  526. HELP0         DB     13,10,'Options:',13,10
  527.               DB     '/OFF - Disable Cache',13,10
  528.               DB     '/ON - Enable Cache',13,10
  529.               DB     '/U - Uninstall Cache',13,10,'$'
  530.  
  531. HELP01        DB     '/Mx - Set Cache Size To x KB',13,10
  532.               DB     '/E - Use EMS',13,10
  533.               DB     '/Hx - Cache Physical Disk x',13,10
  534.               DB     'Defaults: /M64 /H0 /ON',13,10,'$'
  535.  
  536. HELP1         DB     'Invalid Cache Size$'
  537. HELP2         DB     'Already Installed$'
  538. HELP3         DB     'Invalid Command$'
  539. HELP6         DB     'Hard Disk Too Large$'
  540. HELP7         DB     'No EMS Memory$'
  541. HELP8         DB     'EMS Driver Error$'
  542. HELP9         DB     'Invalid Disk$'
  543. HELP10        DB     'Cannot Uninstall$'
  544.  
  545. MSG1          DB     'Cache Installed',13,10,'$'
  546. MSG2          DB     'Not Enough Memory',13,10,'$'
  547.  
  548. COMMANDS      DB     'oumhe'                ;Letters corrsponding to the
  549. COMMANDS_END  =      $                      ;  command line switches.
  550.  
  551. MEM_SIZE_TBL  DB     '16326412255110204081' ;Numbers corresponding to the
  552. MEM_SIZE_TBL_END  =  $                      ;  allowable cache sizes.
  553.  
  554. JUMPTABLE:
  555.               DW     OFFSET CACHE_ON_OFF
  556.               DW     OFFSET UNINSTALL
  557.               DW     OFFSET CACHE_SIZE
  558.               DW     OFFSET DISK_SELECT
  559.               DW     OFFSET EXPANDED_MEM
  560. ;-----------------------------------------------------------------------------
  561. ;Main. This routine performs the instalation, and modification of the cache.
  562. ;-----------------------------------------------------------------------------
  563. MAIN          PROC
  564.               ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
  565. MAIN_ENTRY:
  566. ;-----------------------------------------------------------------------------
  567. ;display program header
  568. ;-----------------------------------------------------------------------------
  569.               MOV    DX,OFFSET PROGRAM
  570.               MOV    AH,9
  571.               INT    21H
  572. ;-----------------------------------------------------------------------------
  573. ;Deallocate environment block
  574. ;-----------------------------------------------------------------------------
  575.               PUSH   ES
  576.               MOV    ES,ENV_SEG             ;Get the segment from the PSP
  577.               ASSUME ES:NOTHING
  578.               MOV    AH,49H                 ;Call dos release memory function.
  579.               INT    21H
  580.               POP    ES
  581.               ASSUME ES:CODE
  582. ;-----------------------------------------------------------------------------
  583. ;check for other copies of this program in memory.
  584. ;-----------------------------------------------------------------------------
  585. FIND_COPIES:
  586.               XOR    BX,BX                  ;Start search a segment 0
  587.               MOV    WORD PTR [ENTRY],BX
  588.               MOV    AX,CS                  ;Get current segment
  589. FIND_LOOP:
  590.               INC    BX                     ;Check next segment
  591.               MOV    ES,BX                  ;Use es as segment pointer
  592.               ASSUME ES:NOTHING
  593.               CMP    AX,BX                  ;Did we find ourselves?
  594.               JE     NO_COPIES              ;Yes, only 1 copy in memory
  595.               MOV    SI,OFFSET ENTRY        ;SI is the offset pointer
  596.               MOV    DI,SI                  ;Look the same place in both segs
  597.               MOV    CX,16                  ;Check 16 bytes
  598.               CLD                           ;Incriment pointers during compare
  599.               REPE   CMPSB                  ;Compare bytes
  600.               JNE    FIND_LOOP              ;If no compare, check another seg
  601.               INC    ALRDY_IN_MEM           ;Set already installed flag
  602. ;--------------------------------------------------------------------------
  603. ;Check for other parameters on the command line.
  604. ;--------------------------------------------------------------------------
  605. NO_COPIES:
  606.               MOV    OTHER_SEG,ES           ;Save the segment of the copy
  607.               PUSH   CS
  608.               POP    ES
  609.               ASSUME ES:CODE
  610.               MOV    DI,OFFSET TAIL_LENGTH  ;Use di to point to command line
  611.               MOV    AX,1234H               ;Set ax to 1234 to indicate if a
  612. FIND_COMMAND:                               ;  command was ever found.
  613.               INC    DI
  614.               DEC    TAIL_LENGTH            ;If we are at the end of the
  615.               JL     FIND_COMMAND_DONE      ;  command line, exit.
  616.               CMP    BYTE PTR [DI],'?'
  617.               JE     DISP_HELP
  618.               CMP    BYTE PTR [DI],'/'      ;if / found a command may
  619.               JNE    FIND_COMMAND           ;  follow.
  620. ;--------------------------------------------------------------------------
  621. ;Figure out what the command is, then process it if possible.
  622. ;--------------------------------------------------------------------------
  623. DECODE_COMMAND:
  624.               MOV    SI,OFFSET COMMANDS     ;Use si to point to the possible
  625.               XOR    BX,BX                  ;  command letters.
  626.               MOV    AL,1[DI]               ;Get command from tail
  627.               OR     AL,20H                 ;Convert uppercase to lower
  628. DECODE_LOOP:
  629.               CMP    AL,[SI]                ;Search the list of allowable
  630.               JE     COMMAND_FOUND          ;  commands.
  631.               INC    BX                     ;If the letters don't match,
  632.               INC    SI                     ;  inc the pointers to the cmd
  633.               CMP    SI,OFFSET COMMANDS_END ;If the command was not found,
  634.               JBE    DECODE_LOOP            ;  display error message.
  635. ILLEGAL_COMMAND:
  636.               MOV    DX,OFFSET HELP3        ;Command unrecognised.
  637.               JMP    SHORT HELP_ROUTINE
  638. COMMAND_FOUND:
  639.               CMP    BL,1                   ;Allow only on, off, and remove
  640.               JLE    COMMAND_FOUND1         ;  if cache already installed.
  641.               CMP    ALRDY_IN_MEM,0
  642.               JNE    DISP_HELP2
  643. COMMAND_FOUND1:
  644.               SAL    BX,1                   ;Convert bx into an index into
  645.               ADD    BX,OFFSET JUMPTABLE    ;  the jump table.
  646.               CALL   [BX]
  647.               JC     HELP_ROUTINE           ;If the carry flag is set on
  648.               JMP    SHORT FIND_COMMAND     ;  return, display error message.
  649. FIND_COMMAND_DONE:
  650.               CMP    ALRDY_IN_MEM,0         ;If not installed, install.
  651.               JE     INSTALL_CACHE
  652.               CMP    AX,1234H               ;Were any commands processed?
  653.               JE     DISP_HELP2             ;No, print already installed msg
  654. TERMINATE:
  655.               MOV    AX,4C00H               ;Terminate with 0 return code.
  656.               INT    21H
  657. ;-----------------------------------------------------------------------------
  658. ;Print help lines.
  659. ;-----------------------------------------------------------------------------
  660. DISP_HELP2:
  661.               MOV    DX,OFFSET HELP2        ;dcache already installed
  662.               JMP    SHORT HELP_ROUTINE
  663. DISP_HELP6:
  664.               MOV    DX,OFFSET HELP6        ;Disk too large
  665. HELP_ROUTINE:
  666.               PUSH   DX                     ;Save offset to message
  667.               MOV    AH,2                   ;Output a carrage return
  668.               MOV    DL,10                  ;  to put a space between
  669.               INT    21H                    ;  the messages.
  670.               POP    DX                     ;Get back offset.
  671.               MOV    AH,9                   ;DOS print string routine
  672.               INT    21H
  673. DISP_HELP:
  674.               MOV    DX,OFFSET HELP0        ;Display possible commands
  675.               MOV    AH,9
  676.               INT    21H
  677.               CMP    ALRDY_IN_MEM,1         ;Check already installed flag
  678.               JE     RETURN_WITH_1
  679.               MOV    DX,OFFSET HELP01       ;If not already installed, print
  680.               MOV    AH,9                   ;  full list of allowable
  681.               INT    21H                    ;  command line switches.
  682. RETURN_WITH_1:
  683.               MOV    AX,4C01H               ;Terminate with 1 return code.
  684.               INT    21H
  685. ;-----------------------------------------------------------------------------
  686. ;Install routine. Compute disk parameters, reserve ems memory if needed,
  687. ;                 compute lookup table size, then jump to install1 routine.
  688. ;-----------------------------------------------------------------------------
  689. INSTALL_CACHE:
  690.               MOV    AH,08H                 ;Read drive parameters
  691.               MOV    DL,DISK_NUM
  692.               INT    13H
  693.               JNC    GOOD_DRIVE             ;Check to insure that a valid
  694.               MOV    DX,OFFSET HELP9        ;  disk has been selected.
  695.               JMP    SHORT HELP_ROUTINE
  696. GOOD_DRIVE:
  697.               MOV    DL,DH
  698.               XOR    DH,DH
  699.               INC    DX
  700.               MOV    MAX_HEAD,DX            ;save maximum head value
  701.               MOV    AX,CX
  702.               AND    CX,003FH
  703.               MOV    MAX_SECTOR,CX          ;save maximum sector value
  704.               XCHG   AH,AL                  ;Compute the largest logical
  705.               ROL    AH,1                   ;  sector value. If the value is
  706.               ROL    AH,1                   ;  larger than 19 bits, display
  707.               AND    AX,03FFH               ;  error message and exit.
  708.               MUL    MAX_HEAD
  709.               ADD    AX,MAX_HEAD
  710.               MUL    MAX_SECTOR
  711.               ADD    AX,MAX_SECTOR
  712.               ADC    DX,0
  713.               CMP    DL,8
  714.               JAE    DISP_HELP6
  715. ;-----------------------------------------------------------------------------
  716. ;Allocate memory for the cache.
  717. ;-----------------------------------------------------------------------------
  718.               MOV    AX,ADDR_MASK           ;Compute amount of memory needed
  719.               INC    AX                     ;  for the cache. To do this,
  720.               INC    AX                     ;  multiply the number of entrys
  721.               MOV    LOOKUP_SIZE,AX         ;  in the lookup table by the
  722.               MOV    CL,PAGE_SIZE           ;  page size and the sector size.
  723.               XOR    CH,CH
  724.               MUL    CX
  725.               MOV    CX,256                 ;Correct for computing twice the
  726.               MUL    CX                     ;  number of lookup table entrys
  727.               MOV    CX,4                   ;  by halving the sector size.
  728. MEM_LOOP1:                                  ;Convert requested memory into
  729.               SHR    DX,1                   ;  paragraphs.
  730.               RCR    AX,1
  731.               LOOP   MEM_LOOP1
  732. ;-----------------------------------------------------------------------------
  733. ;Check which memory to use.
  734. ;-----------------------------------------------------------------------------
  735.               CMP    EMS_FLAG,1
  736.               JNE    GET_DOS_MEM
  737. ;-----------------------------------------------------------------------------
  738. ;Request memory from EMS driver.
  739. ;-----------------------------------------------------------------------------
  740.               MOV    CX,10
  741. EMS_REQ_LOOP1:
  742.               SHR    DX,1                   ;Convert paragraphs to EMS pages.
  743.               RCR    AX,1                   ;  Each page is 16K big.
  744.               LOOP   EMS_REQ_LOOP1
  745. ;-----------------------------------------------------------------------------
  746. ;Check to see if there is enough EMS memory to hold the cache.
  747. ;-----------------------------------------------------------------------------
  748.               MOV    CX,AX                  ;save number of ems pages needed
  749.               MOV    AH,42H
  750.               INT    67H
  751.               OR     AH,AH                  ;check for error
  752.               JNE    EMS_ERROR
  753.               CMP    BX,CX                  ;compare available pages with need
  754.               JAE    GET_EMS_SEG
  755.               JMP    MEMORY_ERROR
  756. ;-----------------------------------------------------------------------------
  757. ;Find out the segment of the EMS page frame.
  758. ;-----------------------------------------------------------------------------
  759. GET_EMS_SEG:
  760.               MOV    AH,41H                 ;get page frame address command
  761.               INT    67H                    ;call EMS driver
  762.               OR     AH,AH                  ;check for error
  763.               JNE    EMS_ERROR
  764.               MOV    CACHE_SEGMENT,BX       ;save page frame segment address
  765.               MOV    MAX_SEGMENT,BX
  766.               MOV    SIZE_MASK,0
  767. ;Request the memory from EMS driver.
  768.               MOV    AH,43H                 ;EMS request memory function
  769.               MOV    BX,CX                  ;put number of EMS pages in bx
  770.               INT    67H                    ;call EMS driver
  771.               OR     AH,AH                  ;check for error
  772.               JNE    EMS_ERROR
  773.               MOV    EMS_HANDLE,DX          ;save EMS handle.
  774.               MOV    AX,ADDR_MASK           ;Create the EMS mask from the
  775.               MOV    CL,3                   ;  addr mask
  776.               SHR    AX,CL
  777.               MOV    EMS_MASK,AX
  778. ;Compute the amount of resident memory needed.
  779.               MOV    DX,LOOKUP_SIZE         ;Get back size of lookup table
  780.               ADD    DX,OFFSET DATA_START+15
  781.               MOV    CL,4
  782.               SHR    DX,CL                  ;convert memory into paragraphs
  783.               MOV    TERM_MEM,DX
  784.               JMP    SHORT PRINT_INSTALL_MSG
  785. ;-----------------------------------------------------------------------------
  786. ;Error routines for memory requests.
  787. ;-----------------------------------------------------------------------------
  788. EMS_ERROR:
  789.               MOV    DX,OFFSET HELP8        ;EMS error
  790.               JMP    HELP_ROUTINE
  791. ;-----------------------------------------------------------------------------
  792. ;Get memory from DOS. Try to reduce memory for program to see if there is
  793. ;  enough memory for the cache.
  794. ;-----------------------------------------------------------------------------
  795. GET_DOS_MEM:
  796. ;-----------------------------------------------------------------------------
  797. ;Move the stack to a safe place inside the cache.
  798. ;-----------------------------------------------------------------------------
  799.               CLI                           ;Inhibit interrupts during this
  800.               MOV    BX,SP                  ;  time.
  801.               MOV    SP,4000H               ;Move the stack pointer down
  802.                                             ;  closer to the code, and well
  803.               STI                           ;  with in the cache memory.
  804. ;-----------------------------------------------------------------------------
  805. ;Check size of cache memory, then reduce current allocation to minimum.
  806. ;-----------------------------------------------------------------------------
  807.               OR     DX,DX                     ;allow cache size <= 512K
  808.               JNE    MEMORY_ERROR              ;  for DOS memory.
  809.               MOV    BX,OFFSET DATA_START+15   ;compute start of cache
  810.               ADD    BX,LOOKUP_SIZE
  811.               MOV    CL,4                   ;convert to segment.
  812.               SAR    BX,CL
  813.               MOV    DX,CS                  ;Get the current code segment
  814.               ADD    DX,BX                  ;Add the converted offset
  815.               MOV    CACHE_SEGMENT,DX       ;save the cache segment
  816. ;-----------------------------------------------------------------------------
  817. ;Continue on with allocating the proper amount of DOS memory.
  818. ;-----------------------------------------------------------------------------
  819.               ADD    BX,AX                  ;Add size of cache.
  820.               MOV    TERM_MEM,BX            ;reduce to amount of memory needed
  821.               MOV    AH,4AH                 ;  at termination of the program.
  822.               INT    21H                    ;DOS reallocate memory function
  823.               JC     MEMORY_ERROR           ;es already points to code seg.
  824. ;-----------------------------------------------------------------------------
  825. ;Create size mask from address mask
  826. ;-----------------------------------------------------------------------------
  827.               MOV    CX,ADDR_MASK           ;The last part of the DOS memory
  828.               XCHG   CH,CL                  ;  installation is to create the
  829.               SHR    CX,1                   ;  size mask needed.
  830.               AND    CX,0FC00H              ;Create size mask from addr mask
  831.               MOV    SIZE_MASK,CX
  832.               MOV    AX,CACHE_SEGMENT
  833.               ADD    AX,CX                  ;Add size mask to cache_segment
  834.               MOV    MAX_SEGMENT,AX         ; register to generate max segment
  835. ;-----------------------------------------------------------------------------
  836. ;Tell user that cache is installed.
  837. ;-----------------------------------------------------------------------------
  838. PRINT_INSTALL_MSG:
  839.               MOV    DX,OFFSET MSG1
  840.               MOV    AH,9
  841.               INT    21H
  842. ;-----------------------------------------------------------------------------
  843. ;Redirect interrupt vector 13.
  844. ;-----------------------------------------------------------------------------
  845.               MOV    AL,ENABLED             ;save the state of the enable flag
  846.               PUSH   AX
  847.               MOV    ENABLED,0              ;disable cache until ready to exit
  848.               MOV    AX,3513H               ;Get the old int 13h vector
  849.               INT    21H
  850.               MOV    OLD_INT13H,BX          ;Save the old vector
  851.               MOV    OLD_INT13H[2],ES
  852.               MOV    DX,OFFSET DISK_INT     ;Point int 13h to cache routine.
  853.               MOV    AX,2513H
  854.               INT    21H
  855. ;-----------------------------------------------------------------------------
  856. ;Terminate but remain resident.
  857. ;-----------------------------------------------------------------------------
  858.               MOV    DX,TERM_MEM            ;get amount of memory needed.
  859.               MOV    AX,3100H               ;Terminate but stay resident
  860.               JMP    INSTALL1               ;jump to location above the
  861.                                             ;  lookup table so it can be
  862.                                             ;  cleared.
  863. ;-----------------------------------------------------------------------------
  864. ;Routine to print installaion error messages.
  865. ;-----------------------------------------------------------------------------
  866. MEMORY_ERROR:
  867.               MOV    DX,OFFSET MSG2         ;Print DOS memory error
  868.               MOV    AH,9
  869.               INT    21H
  870.               MOV    AX,4C02H               ;terminate with rc = 2.
  871.               INT    21H
  872. ;-----------------------------------------------------------------------------
  873. ;Select disk drive to cache
  874. ;-----------------------------------------------------------------------------
  875. DISK_SELECT   PROC   NEAR
  876.               MOV    DL,2[DI]               ;read number after /h
  877.               SUB    DL,30h                 ;convert ascii nubmer to binary
  878.               JL     DISK_SEL_ERR1          ;allow only the numbers 0-9.
  879.               CMP    DL,9
  880.               JA     DISK_SEL_ERR1
  881.               OR     DL,80H                 ;consider only fixed disks
  882.               MOV    DISK_NUM,DL            ;Store drive number
  883.               CLC
  884.               RET
  885. DISK_SEL_ERR1:
  886.               MOV    DX,OFFSET HELP9        ;illegal disk has been selected.
  887.               STC
  888.               RET
  889. DISK_SELECT   ENDP
  890. ;-----------------------------------------------------------------------------
  891. ;Expanded memory select
  892. ;-----------------------------------------------------------------------------
  893. EXPANDED_MEM  PROC   NEAR
  894. ;Test for the EMS driver.
  895.               PUSH   ES
  896.               PUSH   DI
  897.               MOV    AX,3567H               ;Get EMS vector
  898.               INT    21H
  899.               MOV    DI,0AH                 ;Using the segment from the 67h
  900.               MOV    SI,OFFSET EMS_HEADER   ;  vector, look at offset 0ah.
  901.               MOV    CX,8                   ;  Compare the next 8 bytes with
  902.               CLD                           ;  the expected ems header. If
  903.               REPE   CMPSB                  ;  they are the same, allow ems
  904.               POP    DI                     ;  option, else, print error msg.
  905.               POP    ES                     ;Remember, poping registers does
  906.               JNE    EMS_NOT_THERE          ;  not change the flags
  907. ;Set ems indicator.
  908.               INC    EMS_FLAG               ;indicate EMS option
  909.               CLC
  910.               RET                           ;check for more commands
  911. EMS_NOT_THERE:
  912.               MOV    DX,OFFSET HELP7        ;display error message and exit
  913.               STC
  914.               RET
  915. EXPANDED_MEM  ENDP
  916. ;-----------------------------------------------------------------------------
  917. ;Determine the size of the cache.
  918. ;-----------------------------------------------------------------------------
  919. CACHE_SIZE    PROC   NEAR
  920.               MOV    AX,2[DI]               ;get the number after the /m
  921.               MOV    SI,OFFSET MEM_SIZE_TBL
  922.               MOV    CX,2
  923. CACHE_SIZE_LOOP1:
  924.               CMP    AX,[SI]                ;Search the size table to find a
  925.               JE     SIZE_FOUND             ;  match for the size on the
  926.               INC    CX                     ;  command line.
  927.               ADD    SI,2
  928.               CMP    SI,OFFSET MEM_SIZE_TBL_END
  929.               JBE    CACHE_SIZE_LOOP1
  930.               MOV    DX,OFFSET HELP1        ;if size unrecognised, display err
  931.               STC
  932.               RET
  933. SIZE_FOUND:
  934.               XOR    BX,BX                  ;clear register for mask gen.
  935. CACHE_SIZE_LOOP2:
  936.               STC                           ;shift 1's into the low bit of bx
  937.               RCL    BX,1                   ;continue to shift 1's until the
  938.               LOOP   CACHE_SIZE_LOOP2       ;  count id exausted.
  939.               SAL    BX,1
  940.               MOV    ADDR_MASK,BX
  941.               CLC
  942.               RET
  943. CACHE_SIZE    ENDP
  944. ;-----------------------------------------------------------------------------
  945. ;Enable or disable the cache
  946. ;-----------------------------------------------------------------------------
  947. CACHE_ON_OFF  PROC   NEAR
  948.               MOV    AL,2[DI]               ;Get next letter in command line
  949.               CMP    AL,5AH                 ;Convert uppercase to lower
  950.               JA     ON_OFF_SKIP            ;  case if needed.
  951.               ADD    AL,20H
  952. ON_OFF_SKIP:
  953.               XOR    CX,CX
  954.               PUSH   ES
  955.               MOV    ES,OTHER_SEG           ;Get segment of copy (if any)
  956.               ASSUME ES:NOTHING
  957.               CMP    AL,'f'                 ;check second letter for on or off
  958.               JE     CACHE_OFF1
  959.               INC    CX
  960.               CMP    AL,'n'
  961.               JNE    CACHE_ON_OFF_ERR
  962. CACHE_ON1:
  963.               CMP    ALRDY_IN_MEM,CH        ;If initial instalation, don't
  964.               JE     CACHE_OFF1             ;  clear the lookup table here.
  965.               CALL   RESET_CACHE
  966. CACHE_OFF1:
  967.               MOV    ES:ENABLED,CL          ;Set flag to enable cache
  968.               POP    ES
  969.               CLC
  970.               RET
  971. CACHE_ON_OFF_ERR:
  972.               POP    ES
  973.               MOV    DX,OFFSET HELP3        ;indicate an illegal command
  974.               STC
  975.               RET
  976. CACHE_ON_OFF  ENDP
  977.  
  978. ;-----------------------------------------------------------------------------
  979. ; UNINSTALL deallocates the memory block addressed by ES and restores the
  980. ; interrupt 13 vector displaced on installation.
  981. ;   Exit:   CF clear - program uninstalled
  982. ;           CF set   - can't uninstall
  983. ;-----------------------------------------------------------------------------
  984. UNINSTALL        PROC   NEAR
  985.               ASSUME DS:CODE
  986.               PUSH   ES
  987.               MOV    AX,3513H               ;Get int 13 vector
  988.               INT    21H
  989.               MOV    AX,ES                  ;Compare vector segment with
  990.               CMP    AX,OTHER_SEG           ;  segment of installed code.
  991.               JNE    REMOVE_ERR             ;If not the same, can't remove.
  992. ;-----------------------------------------------------------------------------
  993. ;Release the memory occupied by the program. ES already has proper segment.
  994. ;-----------------------------------------------------------------------------
  995.               CMP    ES:EMS_FLAG,0          ;See if EMS memory or conventional
  996.               JE     REMOVE_SKIP1
  997.               MOV    DX,ES:EMS_HANDLE       ;If EMS memory, deallocate using
  998.               MOV    AH,45H                 ;  function 6.
  999.               INT    67H
  1000.               OR     AH,AH
  1001.               JNE    REMOVE_ERR
  1002. REMOVE_SKIP1:
  1003.               MOV    AH,49H                 ;DOS free memory function
  1004.               INT    21H
  1005.               JC     REMOVE_ERR             ;If carry, error on removal
  1006. ;-----------------------------------------------------------------------------
  1007. ;Restore interrupt 13h vector.
  1008. ;-----------------------------------------------------------------------------
  1009.               PUSH   DS
  1010.               LDS    DX,ES:[OLD_DISK_INT]   ;Get old vector from installed
  1011.               MOV    AX,2513H               ;  code.
  1012.               INT    21H                    ;Set int 13 to old vector.
  1013.               POP    DS
  1014.               JC     REMOVE_ERR             ;If error, report and exit.
  1015. ;-----------------------------------------------------------------------------
  1016. ;Destroy the ASCII fingerprint that identifies the code and exit.
  1017. ;-----------------------------------------------------------------------------
  1018.               NOT    WORD PTR ES:[ENTRY]
  1019.               CLC                           ;Clear error flag
  1020. REMOVE_EXIT:
  1021.               POP    ES
  1022.               RET
  1023. ;-----------------------------------------------------------------------------
  1024. ;The program can't be uninstalled.  Set CF and exit.
  1025. ;-----------------------------------------------------------------------------
  1026. REMOVE_ERR:
  1027.               MOV    DX,OFFSET HELP10       ;Point to error message.
  1028.               STC                           ;Set error flag
  1029.               JMP    SHORT REMOVE_EXIT
  1030. UNINSTALL     ENDP
  1031.  
  1032. MAIN          ENDP
  1033. END_OF_PROG   =      $
  1034. CODE          ENDS
  1035.               END    ENTRY
  1036.